{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Distributed Adversarial Training\n",
    "\n",
    "`advsecurenet` library provides a simple and easy-to-use API for adversarial training. In this notebook, we will demonstrate how to use the library to adversarially train a simple neural network on the CIFAR10 dataset. We will use the distributed version of the library in this notebook. It is possible to also use ensemble adversarial training with using multiple models and multiple adversarial attacks."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Using a Configuration File"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 1: Create a Configuration File\n",
    "\n",
    "As a first step, you need to have a default configuration file. You can create a configuration file by running the following command:\n",
    "    \n",
    "```sh\n",
    "advsecurenet utils configs get -c adversarial_training_config.yml -s -o ./default_advsersarial_training_config.yml\n",
    "```\n",
    "\n",
    "Here, we are also providing the `-o` flag to specify the output directory where the configuration file will be saved. You can also specify the output directory by passing the `-o` flag followed by the path to the directory where you want to save the configuration file. If you don't provide the `-o` flag, the configuration file will be saved in the current working directory with the name `adversarial_training_config.yml`. If the file already exists, it will be overwritten. If the output path is a directory, the configuration file will be saved in that directory with the name `adversarial_training_config.yml`.\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!advsecurenet utils configs get -c adversarial_training_config.yml -s -o ./default_advsersarial_training_config.yml"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Let's check the content of the default config file\n",
    "!advsecurenet utils configs get -c adversarial_training_config.yml -p"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 2: Modify the Configuration File\n",
    "\n",
    "The default configuration file is capable of running the adversarial training on the `CIFAR10` dataset using the `ResNet18` model.\n",
    "\n",
    "You can modify the configuration file to run the training on a different dataset, model, or change other hyperparameters. You can also add new hyperparameters to the configuration file.\n",
    "\n",
    "For the sake of this example, we will modify the configuration file to run the training on the `Cifar10` dataset using the `Vgg16` model and the `PGD` attack. To do this, we also need to provide the `PGD` attack configuration yml file in the adversarial training configuration file.\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Step 2.1 Get the PGD Attack Configuration File\n",
    "\n",
    "For the adversarial training, we need to provide the configuration file for the adversarial attack. However, these configuration files are not the same as the configuration files used for the adversarial attack command. The difference is that the configuration files used for the adversarial attack command are used to run the adversarial attack on a model, so they contain the information about the model, dataset, and other hyperparameters. On the other hand, the adversarial attack configuration files used in the adversarial training configuration file contain only the hyperparameters of the adversarial attack since the model and dataset information is already provided in the adversarial training configuration file.\n",
    "\n",
    "Such configuration files have the keyword `base` in the file name. You can get the base configuration file for the `PGD` attack by running the following command:\n",
    "\n",
    "```sh\n",
    "advsecurenet utils configs get -c pgd_attack_base_config.yml -s          \n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!advsecurenet utils configs get -c pgd_attack_base_config.yml -s"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can find the updated configuration file [here](train_config.yml).\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Step 3: Train the Model\n",
    "\n",
    "Now, you can adversarially train the model by running the following command:\n",
    "\n",
    "```sh\n",
    "advsecurenet defense adversarial-training -c ./adversarial_training_config.yml\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!advsecurenet defense adversarial-training -c ./adversarial_training_config.yml"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ensemble Adversarial Training with Multiple Models and Attacks\n",
    "\n",
    "You can also use ensemble adversarial training with multiple models and multiple adversarial attacks. In such cases, adversarial trainer will randomly select a model and an attack for each batch of data. \n",
    "\n",
    "First we need to get the configuration files for the attacks and models we want to use. We already have the configuration file for the `PGD` attack. Now, we will get the configuration file for the `FGSM` attack and the `ResNet18` model. With such setup, the adversarial trainer will randomly select either the `PGD` or the `FGSM` attack and either the `Vgg16` or the `ResNet18` model for each batch of data to adversarially train the source model which is `Vgg16` in this case.\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Get the FGSM attack config file\n",
    "!advsecurenet utils configs get -c fgsm_attack_base_config.yml -s -o ./ensemble/fgsm_attack_config.yml"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Get the model config file\n",
    "!advsecurenet utils configs get -c model_config.yml -s -o ./ensemble/model_config.yml"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can find the updated configuration file for ensemble adversarial training [here](./ensemble/adversarial_training_config_ensemble.yml)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The command to run ensemble adversarial training is the same as the command to run adversarial training. You just need to provide the configuration file for ensemble adversarial training. \n",
    "\n",
    "```sh\n",
    "advsecurenet defense adversarial-training -c ./ensemble/adversarial_training_config_ensemble.yml\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!advsecurenet defense adversarial-training -c ./ensemble/adversarial_training_config_ensemble.yml"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "adv2",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
